package org.xacmlauth.service;

import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.ws.client.core.WebServiceTemplate;
import org.xacmlauth.core.context.RequestType;
import org.xacmlauth.core.domain.EnforceInfo;
import org.xacmlauth.core.domain.EnforceRequest;
import org.xacmlauth.core.domain.PolicyInfo;
import org.xacmlauth.core.domain.RegisterPolicyRequest;
import org.xacmlauth.core.policy.PolicySetType;
import org.xacmlauth.core.policy.PolicyType;
import org.xacmlauth.util.ContextManager;


public class AuthClientImpl implements AuthClient{
	
	private static String webServiceURL;
	
	public AuthClientImpl() throws Exception{
		webServiceURL = "http://localhost:8080/xacmlauth/AuthService";
	}

	@Override
	public String authorize(String clientID, String authRequest) throws Exception {
		EnforceRequest requestPayLoad = new EnforceRequest();
		EnforceInfo enforceInfo = new EnforceInfo();
		enforceInfo.setClientID(clientID);
		
		JAXBContext requestContext = ContextManager.getRequestContext();
		Unmarshaller unmarshaller = requestContext.createUnmarshaller();
		
		JAXBElement<?>  content = (JAXBElement<?>)unmarshaller.unmarshal(new StreamSource(new StringReader(authRequest)));
		RequestType requestType = (RequestType)content.getValue();
		enforceInfo.setRequest(requestType);
		requestPayLoad.setEnforceInfo(enforceInfo);
		
		JAXBContext domainContext = ContextManager.getDomainContext();
		Marshaller marshaller = domainContext.createMarshaller();
		
		StringWriter writer = new StringWriter();
		marshaller.marshal(requestPayLoad, writer);
		String request = writer.toString();
		return callService(request);
	}

	@Override
	public String register(String clientID, String policy) throws Exception {
		RegisterPolicyRequest requestPayLoad = new RegisterPolicyRequest();
		PolicyInfo policyInfo = new PolicyInfo();
		policyInfo.setClientID(clientID);
		
		JAXBContext policyContext = ContextManager.getPolicyContext();
		Unmarshaller unmarshaller = policyContext.createUnmarshaller();

		JAXBElement<?>  content = (JAXBElement<?>)unmarshaller.unmarshal(new StreamSource(new StringReader(policy)));
		Object policyContent = content.getValue();
		PolicyType policyType = null;
		PolicySetType policySetType = null;
		
		if(policyContent instanceof PolicyType){
			policyType = (PolicyType)policyContent;
			policyInfo.setPolicy(policyType);
		}else if(policyContent instanceof PolicySetType){
			policySetType = (PolicySetType)policyContent;
			policyInfo.setPolicySet(policySetType);
		}
		
		requestPayLoad.setPolicyInfo(policyInfo);
		
		StringWriter writer = new StringWriter();
		JAXBContext domainContext = ContextManager.getDomainContext(); 
		Marshaller marshaller = domainContext.createMarshaller();
		marshaller.marshal(requestPayLoad, writer);
		String request = writer.toString();
		
		return callService(request);
	}
	
	private String callService(String request) throws Exception {
		WebServiceTemplate wsTemplate = new WebServiceTemplate();
        
        StreamSource source = new StreamSource(new StringReader(request));
        StringWriter responseWriter = new StringWriter();
        
        StreamResult result = new StreamResult(responseWriter);
		wsTemplate.sendSourceAndReceiveToResult(webServiceURL, source, result);

		return result.getWriter().toString();		
	}

}
